package com.apes.fn.scm.internal.help.service.voucher.retail;

import com.apes.fn.fico.settleExpense.SettleExpense;
import com.apes.fn.fico.settleExpense.SettleExpenseRepository;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailReturn.RetailReturn;
import com.apes.fn.scm.retailReturn.RetailReturnRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.LogicalUtil;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.ReflectUtil;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.contract.service.ContractService;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherInventory;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherInventoryRepository;
import com.apes.scm.voucher.repository.VoucherRepository;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.VoucherType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 委托定损退开票部分
 *  同公司委托定损：只需要写一笔负数的费用单
 *  跨公司委托定损：需要退基地对门店的采购，基地对保险公司的销售
 *
 * @Author wuq
 * @Date 2021-11-16
 */
@Service
public class EntrustLossReturnVoucherService extends DomainService {

    @Autowired
    private SettleExpenseRepository settleExpenseRepository;
    @Autowired
    private VoucherInventoryRepository voucherInventoryRepository;
    @Autowired
    private VoucherRepository voucherRepository;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private ContractService contractService;

    public void createById(SimpleRequest request){
        String id = request.get("id");
        RetailReturn retailReturn = SpringManager.getBean(RetailReturnRepository.class).findOne(id);
        process(retailReturn);
    }

    public void process(RetailReturn retailReturn) {
        if (!"RO003".equals(retailReturn.getSaleOrder().getScene().getId())) return;
        RetailOrder retailOrder = retailReturn.getSaleOrder();

        // 判断是否为同公司委托定损
        if (Objects.equals(retailOrder.getDept().getCompany().getId(), retailOrder.getServiceDept().getCompany().getId())) {
            // 同公司委托定损，直接退费用单
            returnSettleExpense(retailReturn);
        } else {
            // 跨公司委托定损，退基地的采购，退基地对保险公司的分销
            returnCrossEntrustLoss(retailReturn);
        }
    }

    private void returnSettleExpense(RetailReturn retailReturn){
        List<SettleExpense> settleExpenseList = settleExpenseRepository.findAll(
                JpaDsl.toCriteria("source", retailReturn.getSaleOrder().getId(), "origin", retailReturn.getSaleOrder().getSource()));

        settleExpenseList.forEach( settleExpense -> {
            SettleExpense returnExpense = new SettleExpense();
            ReflectUtil.copy(settleExpense, returnExpense,
                    "payment", "dept", "tenant", "type", "platformReturn", "backType", "expenseType", "lossQuotationAmt",
                    "carLicense", "caseType", "origin", "originBusinessType");
            returnExpense.setSource(retailReturn.getId());
            returnExpense.setSourceBusinessType(retailReturn.getInnerBusinessType());
            returnExpense.setRemark("退同公司委托定损费用");
            returnExpense.setAmount( -1 * settleExpense.getAmount());
            settleExpenseRepository.saveAndFlush(returnExpense);
        });
    }

    private void returnCrossEntrustLoss(RetailReturn retailReturn) {
        Voucher originSaleVoucher = voucherRepository.findOne(
                JpaDsl.toCriteriaByEq("classification", "09", "origin", retailReturn.getSaleOrder().getId())).get();
        // 第一步：退对保险公司的销售
        returnSaleVoucher(retailReturn, originSaleVoucher);

        // 第二步：退对门店的采购
        returnPurchaseVoucher(retailReturn, originSaleVoucher);

        // 第三步：退门店对销售公司的账单
        returnStoreInvoice(retailReturn);
    }

    private void returnStoreInvoice(RetailReturn retailReturn){
        // 这里由于在场景流中收货过账时，没有写对应的账单，这里需要补上
        Voucher returnSaleVoucher = voucherRepository.findOne(
                JpaDsl.toCriteriaByEq("classification", "08", "origin", retailReturn.getId(), "source", retailReturn.getId())).get();
        invoke("invoice.create", MapUtil.mapped(invoke("voucher.flow.invoice", MapUtil.mapped(returnSaleVoucher))));
    }

    private void returnSaleVoucher(RetailReturn retailReturn, Voucher originSaleVoucher){
        Voucher voucher = new Voucher();
        // 销售退回必填字段
        voucher.setReturned(true);
        voucher.setBusinessType(BusinessType.SALE_RETURN);
        voucher.setVoucher(originSaleVoucher);

        ReflectUtil.copy(originSaleVoucher, voucher, "dept", "company", "partner", "contract");
        voucher.setInventoryMode(voucher.getContract().getCooperation().getInventoryMode());     //设置库存模式
        voucher.setAccountingMethod(voucher.getContract().getCooperation().getAccountingMethod());  // 核算方式

        voucher.setCustomerExpand(retailReturn.getCustomerExpand().getId());
        voucher.setScene(retailReturn.getScene());
        voucher.setOrigin(retailReturn.getId());
        voucher.setOriginBusinessType(retailReturn.getInnerBusinessType());
        voucher.setSource(retailReturn.getId());
        voucher.setSourceBusinessType(retailReturn.getInnerBusinessType());
        voucher.setClassification(VoucherType.ENTRUST_LOSS_BASE_SALE);

        voucher.setVoucherItems(
                originSaleVoucher.getVoucherItems().stream().map(saleItem -> {
                    VoucherItem voucherItem = new VoucherItem();

                    retailReturn.getSaleItems().stream()
                            .filter(returnItem -> returnItem.getProduct().getId().equals(saleItem.getProduct().getId()))
                            .forEach(retailReturnItem -> {

                                voucherItem.setProduct(saleItem.getProduct());
                                voucherItem.setTax(saleItem.getTax());

                                voucherItem.setUom(saleItem.getUom());          // 设置为销售的单位以及数量
                                voucherItem.setProductQty(-1 * Math.abs(saleItem.getProductQty()));
                                voucherItem.setPriceUnit(saleItem.getPriceUnit());      // 默认为退货单价
                                voucherItem.setOwner(originSaleVoucher.getCompany());

                                voucherItem.setOriginItemId(retailReturnItem.getId());
                                voucherItem.setSourceItemId(retailReturnItem.getId());
                                voucherItem.setVoucherItem(saleItem);   // 退回时传入明细行号
                            });

                    return voucherItem;
                }).filter(voucherItem -> voucherItem.getProduct() != null).collect(Collectors.toSet()));

        voucher = invoke("voucher.create", MapUtil.mapped(voucher));
        createFixedOriginNumberInvoice(retailReturn, voucher);
    }

    private void returnPurchaseVoucher(RetailReturn retailReturn, Voucher originSaleVoucher){
        Voucher voucher = new Voucher();
        voucher.setReturned(true);
        voucher.setBusinessType(BusinessType.PURCHASE_RETURN);

        voucher.setPartner(retailReturn.getCompany().getParty().getPartyRoleByType("Supplier"));
        voucher.setCompany(originSaleVoucher.getCompany());
        voucher.setDept(originSaleVoucher.getDept());
        voucher.setClerk(retailReturn.getClerk());

        Contract contract = contractService.getContract(voucher.getDept(), retailReturn.getCompany(), "distribution", "supplier", "委托定损退货业务");
        voucher.setContract(contract);
        voucher.setInventoryMode(voucher.getContract().getCooperation().getInventoryMode());     //设置库存模式
        voucher.setAccountingMethod(voucher.getContract().getCooperation().getAccountingMethod());  // 核算方式

        voucher.setScene(retailReturn.getScene());
        voucher.setOrigin(retailReturn.getId());
        voucher.setOriginBusinessType(retailReturn.getInnerBusinessType());
        voucher.setSource(retailReturn.getId());
        voucher.setSourceBusinessType(retailReturn.getInnerBusinessType());
        voucher.setCustomerExpand(retailReturn.getCustomerExpand().getId());

        voucher.setVoucherItems(
                retailReturn.getSaleItems().stream()
                        .map(retailReturnItem -> {
                            VoucherItem voucherItem = new VoucherItem();

                            voucherItem.setProduct(retailReturnItem.getProduct());

                            voucherItem.setUom(retailReturnItem.getUom());
                            voucherItem.setProductQty(-1.00 * retailReturnItem.getProductUomQty());
                            voucherItem.setOriginItemId(String.valueOf(retailReturnItem.getId()));
                            voucherItem.setSourceItemId(String.valueOf(retailReturnItem.getId()));

                            //找到原销售凭证的明细行
                            VoucherItem saleVoucherItem = originSaleVoucher.getVoucherItems().stream()
                                    .filter(saleItem -> saleItem.getProduct().getId().equals(retailReturnItem.getProduct().getId()))
                                    .findFirst()
                                    .orElseThrow(() -> new RuntimeException("生成返厂凭证时，根据商品编码没有找到对应的凭证明细，" +
                                            "商品编码：" + retailReturnItem.getProduct().getId() + "，凭证编码：" + originSaleVoucher.getId()));

                            // 获取原销售批次
                            VoucherInventory voucherInventory = voucherInventoryRepository.findAll(
                                    JpaDsl.toCriteriaByEq("voucher.id", originSaleVoucher.getId(), "voucherItem", saleVoucherItem))
                                    .stream().findFirst().get();

                            InventoryBatch inventoryBatch = voucherInventory.getInventoryBatch();
                            voucherItem.setInventoryBatch(inventoryBatch);
                            voucherItem.setPriceUnit(inventoryBatch.getTaxCostPrice());
                            voucherItem.setSupplier(inventoryBatch.getSupplier());
                            voucherItem.setTax(inventoryBatch.getTax());
                            voucherItem.setOwner(originSaleVoucher.getCompany());

                            //  增加（减少）冻结数量
                            inventoryService.changeFrostQty(inventoryBatch, retailReturnItem.getUom(), retailReturnItem.getProductUomQty(), inventoryBatch.getCompany(),
                                    retailReturn.getInnerBusinessType(), retailReturn.getId(), retailReturnItem.getId(), "生成零售服务商品返厂凭证");

                            return voucherItem;
                        }).collect(Collectors.toSet()));

        Voucher newVoucher = invoke("voucher.create", MapUtil.mapped(voucher));
        createFixedOriginNumberInvoice(retailReturn, newVoucher);
    }

    private void createFixedOriginNumberInvoice(RetailReturn retailReturn, Voucher voucher) {
        // 获取 invoice Mapping 文件
        Map m = invoke("voucher.flow.invoice", MapUtil.mapped(voucher));

        m.put("origin", retailReturn.getSaleOrder().getSource());
        m.put("originBusinessType", retailReturn.getSaleOrder().getSourceBusinessType());

        // 生成账单
        invoke("invoice.create", m);
    }
}
